broadway: Use binary websockets if available
authorAlexander Larsson <alexl@redhat.com>
Mon, 1 Oct 2012 12:53:18 +0000 (14:53 +0200)
committerAlexander Larsson <alexl@redhat.com>
Mon, 1 Oct 2012 12:58:57 +0000 (14:58 +0200)
gdk/broadway/broadway.c
gdk/broadway/broadway.h
gdk/broadway/broadway.js
gdk/broadway/gdkdisplay-broadway.c

index 6cbddf4f310cd90c571fd791bda8b841a074dd9e..d16111e06e1a599cfbf5328193a6a0e4507a9920 100644 (file)
@@ -57,6 +57,42 @@ base64_uint32 (guint32 v, char *c)
  *  conversion of raw image data to png data: uris         *
  ***********************************************************/
 
+static cairo_status_t
+write_png_data (void             *closure,
+               const unsigned char *data,
+               unsigned int       data_len)
+{
+  GString *buf = closure;
+
+  g_string_append_len (buf,  (char *)data, data_len);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+to_png_rgb (GString *buf, int w, int h, int byte_stride, guint32 *data)
+{
+  cairo_surface_t *surface;
+
+  surface = cairo_image_surface_create_for_data ((guchar *)data,
+                                                CAIRO_FORMAT_RGB24, w, h, byte_stride);
+
+  cairo_surface_write_to_png_stream (surface, write_png_data, buf);
+  cairo_surface_destroy (surface);
+}
+
+static void
+to_png_rgba (GString *buf, int w, int h, int byte_stride, guint32 *data)
+{
+  cairo_surface_t *surface;
+
+  surface = cairo_image_surface_create_for_data ((guchar *)data,
+                                                CAIRO_FORMAT_ARGB32, w, h, byte_stride);
+
+  cairo_surface_write_to_png_stream (surface, write_png_data, buf);
+  cairo_surface_destroy (surface);
+}
+
 struct PngTarget {
   GString *buf;
   int state;
@@ -101,6 +137,7 @@ to_png_url_rgb (GString *buf, int w, int h, int byte_stride, guint32 *data)
                                                 CAIRO_FORMAT_RGB24, w, h, byte_stride);
 
   cairo_surface_write_to_png_stream (surface, write_png_url, &target);
+  cairo_surface_destroy (surface);
 
   old_len = buf->len;
 
@@ -128,6 +165,7 @@ to_png_url_rgba (GString *buf, int w, int h, int byte_stride, guint32 *data)
                                                 CAIRO_FORMAT_ARGB32, w, h, byte_stride);
 
   cairo_surface_write_to_png_stream (surface, write_png_url, &target);
+  cairo_surface_destroy (surface);
 
   old_len = buf->len;
 
@@ -177,6 +215,7 @@ struct BroadwayOutput {
   int error;
   guint32 serial;
   gboolean proto_v7_plus;
+  gboolean binary;
 };
 
 static void
@@ -235,6 +274,9 @@ broadway_output_flush (BroadwayOutput *output)
 
   if (!output->proto_v7_plus)
     broadway_output_send_cmd_pre_v7 (output, output->buf->str, output->buf->len);
+  else if (output->binary)
+    broadway_output_send_cmd (output, TRUE, BROADWAY_WS_BINARY,
+                             output->buf->str, output->buf->len);
   else
     broadway_output_send_cmd (output, TRUE, BROADWAY_WS_TEXT,
                              output->buf->str, output->buf->len);
@@ -247,7 +289,7 @@ broadway_output_flush (BroadwayOutput *output)
 
 BroadwayOutput *
 broadway_output_new (GOutputStream *out, guint32 serial,
-                    gboolean proto_v7_plus)
+                    gboolean proto_v7_plus, gboolean binary)
 {
   BroadwayOutput *output;
 
@@ -257,6 +299,7 @@ broadway_output_new (GOutputStream *out, guint32 serial,
   output->buf = g_string_new ("");
   output->serial = serial;
   output->proto_v7_plus = proto_v7_plus;
+  output->binary = binary;
 
   return output;
 }
@@ -288,13 +331,19 @@ append_char (BroadwayOutput *output, char c)
 static void
 append_bool (BroadwayOutput *output, gboolean val)
 {
-  g_string_append_c (output->buf, val ? '1': '0');
+  if (output->binary)
+    g_string_append_c (output->buf, val ? 1: 0);
+  else
+    g_string_append_c (output->buf, val ? '1': '0');
 }
 
 static void
 append_flags (BroadwayOutput *output, guint32 val)
 {
-  g_string_append_c (output->buf, val + '0');
+  if (output->binary)
+    g_string_append_c (output->buf, val);
+  else
+    g_string_append_c (output->buf, val + '0');
 }
 
 
@@ -302,22 +351,60 @@ static void
 append_uint16 (BroadwayOutput *output, guint32 v)
 {
   gsize old_len = output->buf->len;
-  g_string_set_size (output->buf, old_len + 3);
-  base64_uint16 (v, output->buf->str + old_len);
+
+  if (output->binary)
+    {
+      guint8 *buf = (guint8 *)output->buf->str + old_len;
+
+      g_string_set_size (output->buf, old_len + 2);
+      buf[0] = (v >> 0) & 0xff;
+      buf[1] = (v >> 8) & 0xff;
+    }
+  else
+    {
+      g_string_set_size (output->buf, old_len + 3);
+      base64_uint16 (v, output->buf->str + old_len);
+    }
 }
 
 static void
 append_uint32 (BroadwayOutput *output, guint32 v)
 {
   gsize old_len = output->buf->len;
-  g_string_set_size (output->buf, old_len + 6);
-  base64_uint32 (v, output->buf->str + old_len);
+
+  if (output->binary)
+    {
+      guint8 *buf = (guint8 *)output->buf->str + old_len;
+
+      g_string_set_size (output->buf, old_len + 4);
+      buf[0] = (v >> 0) & 0xff;
+      buf[1] = (v >> 8) & 0xff;
+      buf[2] = (v >> 16) & 0xff;
+      buf[3] = (v >> 24) & 0xff;
+    }
+  else
+    {
+      g_string_set_size (output->buf, old_len + 6);
+      base64_uint32 (v, output->buf->str + old_len);
+    }
 }
 
 static void
 overwrite_uint32 (BroadwayOutput *output, gsize pos, guint32 v)
 {
-  base64_uint32 (v, output->buf->str + pos);
+  if (output->binary)
+    {
+      guint8 *buf = (guint8 *)output->buf->str + pos;
+
+      buf[0] = (v >> 0) & 0xff;
+      buf[1] = (v >> 8) & 0xff;
+      buf[2] = (v >> 16) & 0xff;
+      buf[3] = (v >> 24) & 0xff;
+    }
+  else
+    {
+      base64_uint32 (v, output->buf->str + pos);
+    }
 }
 
 
@@ -464,7 +551,10 @@ broadway_output_put_rgb (BroadwayOutput *output,  int id, int x, int y,
   append_uint32 (output, 0);
 
   image_start = output->buf->len;
-  to_png_url_rgb (output->buf, w, h, byte_stride, (guint32*)data);
+  if (output->binary)
+    to_png_rgb (output->buf, w, h, byte_stride, (guint32*)data);
+  else
+    to_png_url_rgb (output->buf, w, h, byte_stride, (guint32*)data);
 
   len = output->buf->len - image_start;
 
@@ -719,9 +809,14 @@ broadway_output_put_rgba (BroadwayOutput *output,  int id, int x, int y,
       image_start = output->buf->len;
 
       subdata = (guint8 *)data + rects[i].x1 * 4 + rects[i].y1 * byte_stride;
-      to_png_url_rgba (output->buf, rects[i].x2 - rects[i].x1,
-                      rects[i].y2 - rects[i].y1,
-                      byte_stride, (guint32*)subdata);
+      if (output->binary)
+       to_png_rgba (output->buf, rects[i].x2 - rects[i].x1,
+                    rects[i].y2 - rects[i].y1,
+                    byte_stride, (guint32*)subdata);
+      else
+       to_png_url_rgba (output->buf, rects[i].x2 - rects[i].x1,
+                        rects[i].y2 - rects[i].y1,
+                        byte_stride, (guint32*)subdata);
 
       len = output->buf->len - image_start;
 
index 731e9c1cce3ced17d6ba952f4dfcdcc35471a6bd..e44f332acc6e8b46791a9acc639ce5fb7b8534ee 100644 (file)
@@ -19,7 +19,8 @@ typedef enum {
 
 BroadwayOutput *broadway_output_new             (GOutputStream  *out,
                                                 guint32         serial,
-                                                gboolean        proto_v7_plus);
+                                                gboolean        proto_v7_plus,
+                                                gboolean        binary);
 void            broadway_output_free            (BroadwayOutput *output);
 int             broadway_output_flush           (BroadwayOutput *output);
 int             broadway_output_has_error       (BroadwayOutput *output);
index bd519d0775797eeb5eb22552c07a57f0b781b6c6..cea91dbccd7f73d9066d32d0b93050ddd5553214 100644 (file)
@@ -790,9 +790,10 @@ function handleCommands(cmd)
            q.img.src = url;
            surfaces[q.id].drawQueue.push(q);
            if (!q.img.complete) {
-               q.img.onload = function() { handleOutstanding(); };
+               q.img.onload = function() { cmd.free_image_url (url); handleOutstanding(); };
                return false;
            }
+           cmd.free_image_url (url);
            break;
 
        case 'b': // Copy rects
@@ -886,10 +887,66 @@ TextCommands.prototype.get_image_url = function() {
     this.pos = this.pos + size;
     return url;
 };
+TextCommands.prototype.free_image_url = function(url) {
+};
+
+function BinCommands(message) {
+    this.arraybuffer = message;
+    this.u8 = new Uint8Array(message);
+    this.length = this.u8.length;
+    this.pos = 0;
+}
+
+BinCommands.prototype.get_char = function() {
+    return String.fromCharCode(this.u8[this.pos++]);
+};
+BinCommands.prototype.get_bool = function() {
+    return this.u8[this.pos++] != 0;
+};
+BinCommands.prototype.get_flags = function() {
+    return this.u8[this.pos++];
+}
+BinCommands.prototype.get_16 = function() {
+    var v =
+       this.u8[this.pos] +
+       (this.u8[this.pos+1] << 8);
+    this.pos = this.pos + 2;
+    return v;
+};
+BinCommands.prototype.get_16s = function() {
+    var v = this.get_16 ();
+    if (v > 32767)
+       return v - 65536;
+    else
+       return v;
+};
+BinCommands.prototype.get_32 = function() {
+    var v =
+       this.u8[this.pos] +
+       (this.u8[this.pos+1] << 8) +
+       (this.u8[this.pos+2] << 16) +
+       (this.u8[this.pos+3] << 24);
+    this.pos = this.pos + 4;
+    return v;
+};
+BinCommands.prototype.get_image_url = function() {
+    var size = this.get_32();
+    var png_blob = new Blob ([this.arraybuffer.slice (this.pos, this.pos + size)], {type:"image/png"});
+    var url = URL.createObjectURL(png_blob, {oneTimeOnly: true});
+    this.pos = this.pos + size;
+    return url;
+};
+BinCommands.prototype.free_image_url = function(url) {
+    URL.revokeObjectURL(url);
+};
 
 function handleMessage(message)
 {
-    var cmd = new TextCommands(message);
+    var cmd;
+    if (message instanceof ArrayBuffer)
+       cmd = new BinCommands(message);
+    else
+       cmd = new TextCommands(message);
     outstandingCommands.push(cmd);
     if (outstandingCommands.length == 1) {
        handleOutstanding();
index a6fadd604b5c211b5cc9a661f996cd0aefa65eb4..dba1f55948cbf199174f64065a21ab7751a8836e 100644 (file)
@@ -130,7 +130,7 @@ typedef struct HttpRequest {
   GString *request;
 }  HttpRequest;
 
-static void start_output (HttpRequest *request, gboolean proto_v7_plus);
+static void start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary);
 
 static void
 http_request_free (HttpRequest *request)
@@ -876,7 +876,7 @@ start_input (HttpRequest *request, gboolean binary)
 
   broadway_display->input = input;
 
-  start_output (request, proto_v7_plus);
+  start_output (request, proto_v7_plus, binary);
 
   /* This will free and close the data input stream, but we got all the buffered content already */
   http_request_free (request);
@@ -894,7 +894,7 @@ start_input (HttpRequest *request, gboolean binary)
 }
 
 static void
-start_output (HttpRequest *request, gboolean proto_v7_plus)
+start_output (HttpRequest *request, gboolean proto_v7_plus, gboolean binary)
 {
   GSocket *socket;
   GdkBroadwayDisplay *broadway_display;
@@ -914,7 +914,7 @@ start_output (HttpRequest *request, gboolean proto_v7_plus)
 
   broadway_display->output =
     broadway_output_new (g_io_stream_get_output_stream (G_IO_STREAM (request->connection)),
-                        broadway_display->saved_serial, proto_v7_plus);
+                        broadway_display->saved_serial, proto_v7_plus, binary);
 
   _gdk_broadway_resync_windows ();